import { Component, OnInit, forwardRef, Input, OnDestroy, ChangeDetectionStrategy } from '@angular/core';
import {
  ControlValueAccessor,
  FormBuilder,
  FormControl,
  FormGroup,
  NG_VALIDATORS,
  NG_VALUE_ACCESSOR,
} from '@angular/forms';
import { combineLatest, Observable, Subject, Subscription } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { Identity, IdentityType } from 'src/app/domain';

@Component({
  selector: 'app-identity-input',
  templateUrl: './identity-input.component.html',
  styleUrls: ['./identity-input.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => IdentityInputComponent),
      multi: true,
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => IdentityInputComponent),
      multi: true,
    },
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class IdentityInputComponent implements OnInit, OnDestroy, ControlValueAccessor {

  identityTypes: {value: IdentityType, label: string}[] = [
    {value: IdentityType.IdCard, label: '身份证'},
    {value: IdentityType.Insurance, label: '医保'},
    {value: IdentityType.Passport, label: '护照'},
    {value: IdentityType.Military, label: '军官证'},
    {value: IdentityType.Other, label: '其它'}
  ];

  identity: Identity = {identityType: null, identityNo: null};

  private _idType = new Subject<IdentityType>();
  private _idNo = new Subject<string>();
  private propagateChange = (_: any) => { };
  private _sub: Subscription;


  constructor(private fb: FormBuilder) { }


  ngOnInit() {
    const idType$ = this.idType;
    const idNo$ = this.idNo;
    const val$ = combineLatest(idType$, idNo$, (_type, _no) => {
      return {
        identityType: _type,
        identityNo: _no
      };
    });
    this._sub = val$.subscribe(v => {
      this.identity = v;
      this.propagateChange(v);
    });
  }


  ngOnDestroy() {
    if (this._sub) {
      this._sub.unsubscribe();
    }
  }

  get idType(): Observable<IdentityType> {
    return this._idType.asObservable();
  }

  get idNo(): Observable<string> {
    return this._idNo.asObservable();
  }

  onIdTypeChange(idType: IdentityType) {
    this._idType.next(idType)
  }

  onIdNoChange(idNo: string) {
    this._idNo.next(idNo)
  }

  public writeValue(obj: Identity): void {
    if (obj) {
      this.identity = obj;
    }
  }

  public registerOnChange(fn: any): void {
    this.propagateChange = fn;
  }

  public registerOnTouched(): void { }

  validate(c: FormControl): { [key: string]: any } {
    if (!c.value) {
      return null;
    }
    switch (c.value.identityType) {
      case IdentityType.IdCard: {
        return this.validateIdNumber(c);
      }
      case IdentityType.Passport: {
        return this.validatePassport(c);
      }
      case IdentityType.Military: {
        return this.validateMilitary(c);
      }
      case IdentityType.Insurance:
      default: {
        return null;
      }
    }
  }

  validateIdNumber(c: FormControl): { [key: string]: any } {
    const val = c.value;
    if (val.length !== 18) {
      return {
        idInvalid: true
      }
    }
    const pattern = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}[x0-9]$/;
    return pattern.test(val) ? null : { idNotValid: true }

  }

  validatePassport(c: FormControl): { [key: string]: any } {
    const value = c.value.identityNo;
    if (value.length !== 9) {
      return { idNotValid: true };
    }
    const pattern = /^[GgEe]\d{8}$/;
    let result = false;
    if (pattern.test(value)) {
      result = true;
    }
    return result ? null : { idNotValid: true };
  }

  validateMilitary(c: FormControl): { [key: string]: any } {
    const value = c.value.identityNo;
    const pattern = /[\u4e00-\u9fa5](字第)(\d{4,8})(号?)$/;
    let result = false;
    if (pattern.test(value)) {
      result = true;
    }
    return result ? null : { idNotValid: true };
  }

}
